import logging
from common.user import db as user_db
from common.merchant import merchant_db
from common.merchant import role_db
from common.permission.db import get_role_page_block_field
from common.utils.db import paginate
from common.merchant.models import RoleLevel
from common.utils.maestro_exceptions import (
    MaestroException,
    ACCESS_DENIED
)

_LOGGER = logging.getLogger(__name__)


def get_user_roles_information(user_id):
    """
    :param user_id: 用戶ID
    :return: {
        "root": root_instance if user is root,
        "is_root": true or false,
        "merchant_1": {
            "merchant_name": "loki",
            "role_level": 2,
            "role_id": 4,
            "role": role_instance,
        },
        "merchant_2": ...
    }
    """
    user = user_db.get_user(user_id)
    user_role_list = user.role.split(',')[1:-1]
    user_roles_information = dict(root=None, is_root=False)
    merchants, _ = merchant_db.list_merchant({})
    merchant_dct = {merchant['id']: merchant for merchant in merchants}
    roles, _ = role_db.list_role({'id__in': user_role_list})
    for role in roles:
        if role['role_level'] == RoleLevel.ROOT.value:
            user_roles_information['root'] = role
            user_roles_information['is_root'] = True
        if role['merchant_id'] != 0:
            user_roles_information[role['merchant_id']] = dict(
                merchant_name=merchant_dct[role['merchant_id']]['merchant_name'],
                merchant_label=merchant_dct[role['merchant_id']]['desc'],
                role_level=role['role_level'],
                role_id=role['id'],
                role=role
            )
    if user_roles_information['is_root']:
        for merchant_id, merchant in merchant_dct.items():
            user_roles_information[merchant_id] = dict(
                merchant_name=merchant['merchant_name'],
                merchant_label=merchant['desc'],
                role_level=RoleLevel.ROOT.value,
                role_id=user_roles_information['root']['id'],
                role=user_roles_information["root"]
            )
    return user_roles_information


def _attach_role_name_to_user(role_user, merchant_role_dct, is_noive=False):
    attached_user_list = []
    for user in role_user:
        if not is_noive:
            for key, value in merchant_role_dct.items():
                if ',' + str(key) + ',' in user['role']:
                    user['role_name'] = value
        else:
            user['role'] = '游客账号'
            user['role_name'] = '游客账号'
        attached_user_list.append(user)
    return attached_user_list


def _get_merchant_novice_users(merchant_id, user_filter):
    merchant_roles, _ = role_db.list_role({'merchant_id': merchant_id})
    root_id_list = [role['id'] for role in role_db.list_role({'role_level': 0})[0]]
    merchant_role_id_list = [role['id'] for role in merchant_roles]
    novice_users, novice_users_count = user_db.get_role_user(merchant_role_id_list + root_id_list,
                                                             user_filter_dct=user_filter, exclude=True)
    novice_users = _attach_role_name_to_user(novice_users, {}, is_noive=True)
    return novice_users, novice_users_count


def _get_merchant_role_users(merchant_id, user_role_id, user_is_root, target_roles, user_filter):
    role_query_dct = {'merchant_id': merchant_id}
    target_role_id = target_roles
    if not user_is_root:
        child_role_items, _ = role_db.list_role({'supervisor_id': user_role_id})
        child_role_id = [role['id'] for role in child_role_items]
        if target_roles:
            for role_id in target_roles:
                if role_id not in child_role_id and role_id != 'novice':
                    raise MaestroException(ACCESS_DENIED)
        else:
            target_role_id = child_role_id
    if target_role_id:
        role_query_dct['id__in'] = target_role_id
    merchant_roles, _ = role_db.list_role(role_query_dct)
    merchant_role_dct = {role['id']: role['role_name'] for role in merchant_roles}
    role_users, role_users_count = user_db.get_role_user(merchant_role_dct.keys(), user_filter)
    role_users = _attach_role_name_to_user(role_users, merchant_role_dct)
    return role_users, role_users_count


def list_merchant_user(merchant_id, user_id, target_roles=None, user_filter=None, paginate_dct=None):
    user_role = get_user_roles_information(user_id)
    user_role_id_in_merchant = user_role.get(merchant_id, {}).get('role_id')
    is_root = user_role.get('is_root', False)
    if not user_role_id_in_merchant and not is_root:
        raise MaestroException(ACCESS_DENIED)
    role_users, role_users_count = _get_merchant_role_users(merchant_id, user_role_id_in_merchant, is_root,
                                                            target_roles, user_filter)
    if 'novices' in target_roles or not target_roles:
        novice_users, novice_users_count = _get_merchant_novice_users(merchant_id, user_filter)
        role_users = list(role_users) + list(novice_users)
        role_users_count = role_users_count + novice_users_count
    if paginate_dct:
        role_users = paginate(role_users, paginate_dct)
    for role_user in role_users:
        role_user['desc'] = user_db.get_user_description(role_user['id'], merchant_id, user_id)
    resp_items = []
    for item in role_users:
        if item['role']:
            item['merchant_role'] = role_db.get_user_merchant_role(merchant_id, item['role']).get('id')
        item['updated_at'], item['created_at'] = str(item['updated_at']), str(item['created_at'])
        item.pop('password', None)
        resp_items.append(item)
    return dict(list=resp_items, page=paginate_dct.get('page', 1), size=len(resp_items), total_count=role_users_count)


def get_supervisor_list(merchant_id):
    root = role_db.get_role({'role_level': RoleLevel.ROOT.value})
    merchant_managers, _ = role_db.list_role({'merchant_id': merchant_id, 'role_level': RoleLevel.MANAGER.value})
    supervisor_list = [{'key': role['id'], 'value': role['role_name']} for role in merchant_managers]
    return [{'key': root.id, 'value': root.role_name}] + supervisor_list


def get_visible_roles(merchant_id, user_role_dct, base_query_dct=None):
    query_dct = base_query_dct if base_query_dct else {}
    if user_role_dct['role_level'] == RoleLevel.ROOT.value:
        query_dct.update({'merchant_id': merchant_id})
    else:
        query_dct.update({'merchant_id': merchant_id, 'supervisor_id': user_role_dct['id']})
    visible_roles, total_count = role_db.list_role(query_dct)
    supervisor_id_list = [role['supervisor_id'] for role in visible_roles]
    supervisor_roles, _ = role_db.list_role({'id__in': supervisor_id_list})
    supervisor_id_name_dct = {role['id']: role['role_name'] for role in supervisor_roles}
    resp_items = []
    for role in visible_roles:
        role_perm = role['perm'].split(',')[1:-1] if role['perm'] else []
        role['perm'] = [{'key': perm, 'exclude_name': get_role_page_block_field(merchant_id, role['id'], perm)}
                        for perm in role_perm]
        role['created_at'] = str(role['created_at'])
        role['updated_at'] = str(role['updated_at'])
        role['supervisor_name'] = supervisor_id_name_dct.get(role['supervisor_id'])
        resp_items.append(role)
    return dict(list=resp_items, page=query_dct.get('$page', 1), size=len(resp_items), total_count=total_count)
